package com.moon.icoresso.controller;

import com.moon.icoresso.Exception.OauthException;
import com.moon.icoresso.Service.OauthRedisService;
import com.moon.icoresso.Service.OauthService;
import com.moon.icoresso.api.UserInfoApi;
import com.moon.icoresso.common.utils.CookieUtils;
import com.moon.icoresso.common.utils.StringRedisService;
import com.moon.icoresso.common.utils.StringUtil;
import com.moon.icoresso.pojo.bo.OauthAccessTokenToRedisBO;
import com.moon.icoresso.pojo.bo.OauthToRedisBO;
import com.moon.icoresso.pojo.bo.OauthTokenHandleBO;
import com.moon.icoresso.pojo.constants.Constants4Oauth;
import com.moon.icoresso.pojo.dto.*;
import com.moon.icoresso.strategy.OauthTokenStrategyContext;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

import static com.moon.icoresso.pojo.constants.Constants4Oauth.*;

/**
 * @ClassName OauthController
 * @Description
 * @Author menbbo
 * @Date 2021/2/12 16:13
 * @Version V1.0
 **/
@RestController
public class OauthController {
    @Autowired
    private OauthService oauthService;

    @Autowired
    private OauthRedisService oauthRedisService;

    @Autowired
    private UserInfoApi userInfoApi;

    @Autowired
    private OauthTokenStrategyContext oauthTokenStrategyContext;
    @Autowired
    private StringRedisService<String,OauthAccessTokenToRedisBO> tokenRedisService;
    @RequestMapping(value = "/authorize",method = RequestMethod.POST)
    public String authorize(final HttpServletRequest request, final HttpServletResponse response, @RequestBody(required = false) UserDTO userDTO){
        OauthUserInfo oauthUserInfo;
        try {
            //判断clientId与RedirectUri是否符合要求
            OauthToRedisBO clientId = oauthService.checkClientIdAndRedirectUri(userDTO);
            oauthService.checkUserAgent(request.getHeader(Constants4Oauth.USER_AGENT));
            //校验用户名与密码
            oauthService.checkUserDTO(userDTO);
            //对用户
            oauthUserInfo = userInfoApi.getUserInfoByUserIdAndPassword(userDTO.getUserId(),userDTO.getPassword());
        }catch (OauthException e){
            return e.getMessage();
        }
        //根据userId生成redisKey
        String userInfoKey = oauthRedisService.generateUserInfoRedisKey(userDTO.getUserId());
        oauthRedisService.saveUserInfo(userInfoKey,oauthUserInfo,MAX_EXPIRE_TIME, TimeUnit.SECONDS);

        //授权码模式
        String code = oauthService.generateCode();
        oauthRedisService.saveOauthCode(code,userDTO.getClientId(),null,userInfoKey);
        CookieUtils.setCookie(response,"code",code,2000,true,true);
        String redirectUri = generateRedirectUri(userDTO.getRedirectUri(), code);
        return redirectUri;
    }
    private String generateRedirectUri(String redirectUri,String code){
        return redirectUri + "?"+"code=" +code;
    }

    @RequestMapping(value = "/token",method = RequestMethod.POST)
    public ResponseDTO<OauthTokenDTO> getToken(final HttpServletRequest request, @RequestBody OauthTokenParam oauthTokenParam){
        OauthTokenDTO oauthTokenDTO = null;
        try{
            oauthService.checkGrantType(oauthTokenParam.getGrantType());
            OauthTokenHandleBO oauthTokenHandleBO = new OauthTokenHandleBO();

            //模拟获取用户信息
            OauthUserInfo oauthUserInfo = new OauthUserInfo();
            oauthUserInfo.setTel("151910");
            oauthUserInfo.setEmail("123@163.com");
            oauthUserInfo.setUserName("赵四");
            oauthTokenHandleBO.setOauthUserInfo(oauthUserInfo);

            oauthTokenStrategyContext.checkParam(oauthTokenParam.getGrantType(),oauthTokenParam,oauthTokenHandleBO);
            oauthTokenDTO = oauthTokenStrategyContext.generateToken(oauthTokenParam.getGrantType(), oauthTokenParam, oauthTokenHandleBO);
            oauthTokenDTO.setTokenType(oauthTokenParam.getGrantType());
        }catch (OauthException e){
            return new ResponseDTO<OauthTokenDTO>().error(e.getMessage());
        }catch (Exception e){
            return new ResponseDTO<OauthTokenDTO>().error(e.getMessage());
        }
        return new ResponseDTO<OauthTokenDTO>().success(oauthTokenDTO);
    }

    @RequestMapping(value = "/getUserInfo",method = {RequestMethod.POST,RequestMethod.GET})
    public ResponseDTO<OauthUserInfo> userInfo(HttpServletRequest request){
        //参数验证 验证token是否合法
        try{
            OauthAccessTokenToRedisBO oauthAccessTokenToRedisBO = oauthService.checkRequestParam(request);
            OauthUserInfo oauthUserInfo = oauthAccessTokenToRedisBO.getOauthUserInfo();
            return new ResponseDTO<OauthUserInfo>().success(oauthUserInfo);
        }catch (Exception e) {
            return new ResponseDTO<OauthUserInfo>().error(e.getMessage());
        }
    }


    /**
     * 验证token有效性
     * @param request
     * @param oauthTokenVerifyParam
     * @return
     */
    @RequestMapping(value = "/verifyToken")
    public ResponseDTO<?> verfiyToken(HttpServletRequest request,@RequestBody OauthTokenVerifyParam oauthTokenVerifyParam){
        OauthClient oauthClient = new OauthClient();
        resolveRequestHeader(request,oauthClient);
        oauthService.checkOauthTokenVerifyParam(oauthTokenVerifyParam);
        if(StringUtils.equalsIgnoreCase(oauthTokenVerifyParam.getType(),ACCESS_TOKEN_TYPE)){
           if(getToken(oauthTokenVerifyParam.getToken())==null){
                return new ResponseDTO().error("access_token失效");
            }
        }else if(StringUtils.equalsIgnoreCase(oauthTokenVerifyParam.getType(),REFRESH_TOKEN_TYPE)){
            if(getToken(oauthTokenVerifyParam.getToken())==null){
                return new ResponseDTO().error("refresh_token失效");
            }
        }else {
            //
        }
        return new ResponseDTO<>().success("token有效");
    }

    private OauthAccessTokenToRedisBO getToken(String token){
        OauthAccessTokenToRedisBO oauthAccessTokenToRedisBO = tokenRedisService.get(token);
        return oauthAccessTokenToRedisBO;
    }
    /**
     * 从请求头解析clientId和clientSecret
     * @param request
     */
    private void resolveRequestHeader(HttpServletRequest request,OauthClient oauthClient){
        String authorizationHeader = request.getHeader(HEADER_AUTHORIZATION);
        if(StringUtils.isEmpty(authorizationHeader)){
            throw new OauthException("clientId为空");
        }
        String client = null;
        if(StringUtils.containsIgnoreCase(authorizationHeader,PREFIX_UPPER_CLIENT)){
            String replaceHeader = StringUtils.replace(authorizationHeader,PREFIX_UPPER_CLIENT,PREFIX_LOWER_CLIENT);
            client = StringUtils.substringAfter(replaceHeader, PREFIX_LOWER_CLIENT);
        }else {
            client = authorizationHeader;
        }
        //base64解密,可以使用过国密算法
        String resultEncode =new String(Base64.decodeBase64(client));
        String[] basic = StringUtils.split(resultEncode, ":");
        if(basic.length<2){
            return;
        }
        oauthClient.setClientId(basic[0]);
        oauthClient.setClientSecret(basic[1]);
    }

}